package com.cert;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.security.MessageDigest;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
 
 
public class DownloadHttpsCert {
	static String proxyHost = "https://web.cupdata.com";
	static int proxyPort = 80;
	static String proxyUser = "";
	static String proxyPassword = "";
 
	public static void setAuthenticator() {
		Authenticator authenticator = new Authenticator() {
			public PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(proxyUser, proxyPassword.toCharArray());
			}
		};
		Authenticator.setDefault(authenticator);
	}
 
//	public static void main(String[] args) throws Exception {
// 
//		String host = "https://web.cupdata.com";
//		int port = 443;
//		File file = new File(System.getProperty("java.home") + File.separator + "lib" + File.separator + "security/cacerts");
//		String keyStorePassword = "changeit";
// 
//		// 新建一个信任管理工厂，信任仓库为jre的cacerts文件
//		KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
//		ks.load(new FileInputStream(file), keyStorePassword.toCharArray());
//		TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//		tmf.init(ks);
// 
//		System.out.println(tmf.getTrustManagers().length);
//		// 获取信任管理类的第一个(调试代码时发现也只有一个)
//		X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
//		// 改写第一个，从而能够拿到服务器发送过来的证书
//		SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
// 
//		SSLContext context = SSLContext.getInstance("TLS");
//		context.init(null, new TrustManager[] { tm }, null);
//		SSLSocketFactory factory = context.getSocketFactory();
// 
//		// httpUrlConnection写法
//		{
//			SocketAddress proxyInetAddress = new InetSocketAddress(proxyHost, proxyPort);
//			Proxy proxy = new Proxy(Proxy.Type.HTTP, proxyInetAddress);
//			URL url = new URI("https", null, host, port, "", null, null).toURL();
//			HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(proxy);
//			connection.setConnectTimeout(10 * 1000);
//			connection.setSSLSocketFactory(factory);
//			connection.setRequestMethod("GET");
//			
//			//第一种设置代理密码的方法 （测试无效）
////			System.setProperty("https.proxyUser", proxyUser);
////			System.setProperty("https.proxyPassword", proxyPassword);
//			
//			//第二种写法  测试无效(抓包发现根本就不会带这个header)
////			String key = "Proxy-Authorization";
////			String base64 = Base64.getEncoder().encodeToString((proxyUser + ":" + proxyPassword).getBytes()); 
////			String value = "Basic " + base64;
////			connection.setRequestProperty(key, value);
//			
//			//第三种写法 测试有效(如果还有错请继续看文章后面介绍)
//			setAuthenticator();
//			
//			try{
//				connection.connect();
//				System.out.println("no error,certificate is already trusted.");
//			} catch(SSLException e){
//				System.out.println("catch SSLException.");
//			}
//		}
// 
//		// socket 写法
//		// {
//		// SSLSocket socket;
//		// boolean useProxy = true;
//		// if(useProxy) {//设置代理
//		// SocketAddress proxyInetAddress = new
//		// InetSocketAddress(proxyHost,proxyPort);
//		// Proxy proxy = new Proxy(Proxy.Type.HTTP,proxyInetAddress);
//		// Socket orginSocket = new Socket(proxy);
//		//
//		// SocketAddress server = new InetSocketAddress(host,port);
//		//
//		// setAuthenticator();//密码认证必须放在连接之前
//		//
//		// //这句话非常重要，之前就是因为没写这句话，花了一两个小时的时间才找
//		// //到这个函数加上去（不过还是有些成就感，网上没找到相关代码，这句话是自己摸索出来的）
//		// orginSocket.connect(server);
//		//
//		// socket = (SSLSocket) factory.createSocket(orginSocket, host, port,
//		// true);
//		// }else{
//		// socket = (SSLSocket)factory.createSocket(host, port);
//		// }
//		// socket.setSoTimeout(10000);
//		// try {
//		// //握手的过程中服务器会发送证书过来
//		// socket.startHandshake();
//		// socket.close();
//		// //如果证书没有被信任，上面握手的代码会抛出异常
//		// System.out.println("No errors, certificate is already trusted");
//		// } catch (SSLException e) {
//		// //e.printStackTrace(System.out);
//		// System.out.println("SSLException.begin download cacerts.");
//		// }
//		// }
// 
//		// 完成握手之后，
//		X509Certificate[] chain = tm.chain;
//		if (chain == null) {
//			throw new RuntimeException("Could not obtain server certificate chain");
//		}
//		System.out.println("received " + chain.length + " certificate(s) from server:");
// 
//		MessageDigest sha1 = MessageDigest.getInstance("SHA1");
//		MessageDigest md5 = MessageDigest.getInstance("MD5");
//		for (int i = 0; i < chain.length; i++) {
//			X509Certificate cert = chain[i];
//			System.out.println(" " + (i + 1) + " Subject " + cert.getSubjectDN());
//			System.out.println("   Issuer  " + cert.getIssuerDN());
//			sha1.update(cert.getEncoded());
//			System.out.println("   sha1    " + toHexString(sha1.digest()));
//			md5.update(cert.getEncoded());
//			System.out.println("   md5     " + toHexString(md5.digest()));
//			System.out.println();
//		}
// 
//		// 只导入服务器发来的第一个证书。当然可以导入多个
//		int k = 0;
//		X509Certificate cert = chain[k];
//		String alias = host + "-" + (k + 1);
//		ks.setCertificateEntry(alias, cert);
// 
//		// 将keystore中的证书条目输出到文件中
//		OutputStream out = new FileOutputStream("jssecacerts");
//		ks.store(out, keyStorePassword.toCharArray());
//		out.close();
// 
//		System.out.println("Added certificate to keystore 'jssecacerts'，alias：" + alias);
//	}
	
	 public static void main(String[] args) throws Exception {
         URL url = new URL("https://web.cupdata.com");
         HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
         conn.connect();
         Certificate[] certs = conn.getServerCertificates();    //会拿到完整的证书链
         
         
         X509Certificate cert = (X509Certificate)certs[0];    //cert[0]是证书链的最下层
         System.out.println("序号：" + cert.getSerialNumber());
         System.out.println("颁发给：" + cert.getSubjectDN().getName());
         System.out.println("颁发者：" + cert.getIssuerDN().getName());
         System.out.println("起始：" + cert.getNotBefore());
         System.out.println("过期：" + cert.getNotAfter());
         System.out.println("算法：" + cert.getSigAlgName());
         System.out.println("指纹：" + getThumbPrint(cert));
         System.out.println("PublicKey：" + cert.getPublicKey().getEncoded()); 
         conn.disconnect();
     }
  
	 public static X509Certificate getCert() throws Exception {
         URL url = new URL("https://web.cupdata.com/");
         HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
         conn.connect();
         Certificate[] certs = conn.getServerCertificates();    //会拿到完整的证书链
         
         
         X509Certificate cert = (X509Certificate)certs[0];    //cert[0]是证书链的最下层
         System.out.println("序号：" + cert.getSerialNumber());
         System.out.println("颁发给：" + cert.getSubjectDN().getName());
         System.out.println("颁发者：" + cert.getIssuerDN().getName());
         System.out.println("起始：" + cert.getNotBefore());
         System.out.println("过期：" + cert.getNotAfter());
         System.out.println("算法：" + cert.getSigAlgName());
         System.out.println("指纹：" + getThumbPrint(cert));
         conn.disconnect();
		return cert;
     }
  
	 
     private static String getThumbPrint(X509Certificate cert) throws Exception {
         MessageDigest md = MessageDigest.getInstance("SHA-1");
         byte[] der = cert.getEncoded();
         md.update(der);
         byte[] digest = md.digest();
         return bytesToHexString(digest);
     }
      
     private static String bytesToHexString(byte[] src) {
         StringBuilder stringBuilder = new StringBuilder("");
         if (src == null || src.length <= 0) {
             return null;
         }
         for (int i = 0; i < src.length; i++) {
             int v = src[i] & 0xFF;
             String hv = Integer.toHexString(v);
             if (hv.length() < 2) {
                 stringBuilder.append(0);
             }
             stringBuilder.append(hv);
         }
         return stringBuilder.toString();
     }
 
	private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
 
	public static String toHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (int b : bytes) {
			b &= 0xff;
			sb.append(HEXDIGITS[b >> 4]);
			sb.append(HEXDIGITS[b & 15]);
		}
		return sb.toString();
	}
}
